(*LABLGL ET .OBJ*)

(* init de lablGL *)

let split = Str.split (Str.regexp_string " ")

let rec read vs is ch =
  match try Some(split (input_line ch)) with _ -> None with
  | None -> vs, is
  | Some[x;y;z;_;_] -> read ((float_of_string x, float_of_string y, float_of_string z) :: vs) is ch
  | Some["3";i;j;k] -> read vs ((int_of_string i,int_of_string j,int_of_string k) :: is) ch
  | Some s -> read vs is ch

let vertices, indices =
  let ch = open_in "/home/huyghe_k/data/bun_zipper.ply" in
  let vs, is = read [] [] ch in
  close_in ch;
  Printf.printf "%d vertices, %d triangles\n%!"
    (List.length vs) (List.length is);
  Array.of_list (List.rev vs), is

let ( +| ) (x0, y0, z0) (x1, y1, z1) = x0 +. x1, y0 +. y1, z0 +. z1
let ( -| ) (x0, y0, z0) (x1, y1, z1) = x0 -. x1, y0 -. y1, z0 -. z1
let ( *| ) s (x, y, z) = s *. x, s *. y, s *. z
let dot (x0, y0, z0) (x1, y1, z1) = x0 *. x1 +. y0 *. y1 +. z0 *. z1
let norm r = 1. /. sqrt(dot r r) *| r
let cross (x0, y0, z0) (x1, y1, z1) =
  z0 *. y1 -. z1 *. y0, x0 *. z1 -. x1 *. z0, y0 *. x1 -. y1 *. x0

let normals =
  let vs = vertices in
  let ns = Array.make (Array.length vs) (0., 0., 0.) in
  let aux (i, j, k) =
    let n = norm(cross (vs.(j) -| vs.(i)) (vs.(k) -| vs.(i))) in
    List.iter (fun i -> ns.(i) <- ns.(i) +| n) [i;j;k] in
  List.iter aux indices;
  Array.map norm ns

let time =
  let start = Unix.gettimeofday () in
  fun () -> Unix.gettimeofday () -. start

let draw_triangle (i, j, k) =
  List.iter (fun i -> GlDraw.normal3 normals.(i);
	       GlDraw.vertex3 vertices.(i)) [i;j;k]

let draw_bunny() =
  GlDraw.begins `triangles;
  List.iter draw_triangle indices;
  GlDraw.ends()

let memoize f =
  let display_list = ref None in
  fun () -> match !display_list with
  | Some list -> GlList.call list
  | None ->
      display_list := Some (GlList.create `compile);
      f();
      GlList.ends ()

let draw_bunny = memoize draw_bunny

let width = ref 1 and height = ref 1

let reshape ~w ~h =
  width := max 1 w;
  height := max 1 h;
  GlDraw.viewport 0 0 w h

let ot = ref (int_of_float (time()))
let frames = ref 0

let render() =
  incr frames;
  let t = int_of_float (time()) in
  if t <> !ot then begin
    Printf.printf "%d fps\n%!" !frames;
    frames := 0;
    ot := t
  end;
  GlClear.clear [`color; `depth];

  Gl.enable `depth_test;

  GlMat.mode `projection;
  GlMat.load_identity ();
  let aspect = float !width /. float !height in
  GluMat.perspective ~fovy:45.0 ~aspect ~z:(0.1, 1.);
  GluMat.look_at ~eye:(0., 0.12, -0.25) ~center:(0., 0.1, 0.) ~up:(0., 1., 0.);
  GlMat.mode `modelview;
  GlMat.load_identity ();

  Gl.enable `lighting;
  Gl.enable `light0;
  GlLight.light ~num:0 (`position (1., -1., 1., 1.));

  GlMat.rotate3 (15. *. time()) (0., 1., 0.);
  GlLight.material `both (`shininess 100.);
  Gl.enable `color_material;
  GlLight.color_material `both `specular;
  GlLight.color_material `both `ambient_and_diffuse;
  GlDraw.color (0.5, 0.4, 0.4);

  draw_bunny();

  Gl.flush ();
  Glut.swapBuffers ()

let _ =
  let _ = Glut.init Sys.argv in
  Glut.initDisplayMode ~depth:true ~double_buffer:true ();
  let _ = Glut.createWindow ~title:"Stanford bunny" in
  Glut.reshapeFunc ~cb:reshape;
  Glut.displayFunc ~cb:render;
  Glut.idleFunc ~cb:(Some Glut.postRedisplay);
  Glut.keyboardFunc ~cb:(fun ~key ~x ~y -> if key=27 then exit 0);
  Glut.mainLoop ()

(*END*)
